#include "pf_meshline.h"

namespace CommonFEM {

PF_MeshLine::PF_MeshLine(PF_GraphicView *parentPlot) :
    QCPAbstractItem(parentPlot)
{
    setPen(QPen(Qt::black));
    setSelectedPen(QPen(Qt::blue,2));
}

PF_MeshLine::~PF_MeshLine()
{

}

void PF_MeshLine::setPen(const QPen &pen)
{
    mPen = pen;
}

void PF_MeshLine::setSelectedPen(const QPen &pen)
{
    mSelectedPen = pen;
}

void PF_MeshLine::clearLines()
{
    for(auto l : m_linelist){
        if(l) delete l;
    }
    m_linelist.clear();
}

void PF_MeshLine::addLine(double x1, double y1, double x2, double y2)
{
    auto l = new Line(x1,y1,x2,y2);
    m_linelist.append(l);
}

double PF_MeshLine::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const
{
    return -1;
}

void PF_MeshLine::draw(QCPPainter *painter)
{
    if(!(painter && mParentPlot)){
        qDebug()<<Q_FUNC_INFO<<":NULL";
        return;
    }
    painter->save();
    for(auto l : m_linelist){
        QPointF start(mParentPlot->toGuiX(l->m_x1),mParentPlot->toGuiY(l->m_y1));
        QPointF end(mParentPlot->toGuiX(l->m_x2),mParentPlot->toGuiY(l->m_y2));
        painter->drawLine(start,end);
    }
//    QVector2D startVec(start->pixelPoint());
//    QVector2D endVec(end->pixelPoint());
//    if (startVec.toPoint() == endVec.toPoint())
//        return;
//    // get visible segment of straight line inside clipRect:
//    double clipPad = qMax(mHead.boundingDistance(), mTail.boundingDistance());
//    clipPad = qMax(clipPad, (double)mainPen().widthF());
//    QLineF line = getRectClippedLine(startVec, endVec, clipRect().adjusted(-clipPad, -clipPad, clipPad, clipPad));
//    // paint visible segment, if existent:
//    if (!line.isNull())
//    {
//        painter->setPen(mainPen());
//        painter->drawLine(line);
//    }
    painter->restore();
}


QLineF PF_MeshLine::getRectClippedLine(const QVector2D &start, const QVector2D &end, const QRect &rect) const
{
    bool containsStart = rect.contains(start.x(), start.y());
    bool containsEnd = rect.contains(end.x(), end.y());
    if (containsStart && containsEnd)
        return QLineF(start.toPointF(), end.toPointF());

    QVector2D base = start;
    QVector2D vec = end-start;
    double bx, by;
    double gamma, mu;
    QLineF result;
    QList<QVector2D> pointVectors;

    if (!qFuzzyIsNull(vec.y())) // line is not horizontal
    {
        // check top of rect:
        bx = rect.left();
        by = rect.top();
        mu = (by-base.y())/vec.y();
        if (mu >= 0 && mu <= 1)
        {
            gamma = base.x()-bx + mu*vec.x();
            if (gamma >= 0 && gamma <= rect.width())
                pointVectors.append(QVector2D(bx+gamma, by));
        }
        // check bottom of rect:
        bx = rect.left();
        by = rect.bottom();
        mu = (by-base.y())/vec.y();
        if (mu >= 0 && mu <= 1)
        {
            gamma = base.x()-bx + mu*vec.x();
            if (gamma >= 0 && gamma <= rect.width())
                pointVectors.append(QVector2D(bx+gamma, by));
        }
    }
    if (!qFuzzyIsNull(vec.x())) // line is not vertical
    {
        // check left of rect:
        bx = rect.left();
        by = rect.top();
        mu = (bx-base.x())/vec.x();
        if (mu >= 0 && mu <= 1)
        {
            gamma = base.y()-by + mu*vec.y();
            if (gamma >= 0 && gamma <= rect.height())
                pointVectors.append(QVector2D(bx, by+gamma));
        }
        // check right of rect:
        bx = rect.right();
        by = rect.top();
        mu = (bx-base.x())/vec.x();
        if (mu >= 0 && mu <= 1)
        {
            gamma = base.y()-by + mu*vec.y();
            if (gamma >= 0 && gamma <= rect.height())
                pointVectors.append(QVector2D(bx, by+gamma));
        }
    }

    if (containsStart)
        pointVectors.append(start);
    if (containsEnd)
        pointVectors.append(end);

    // evaluate points:
    if (pointVectors.size() == 2)
    {
        result.setPoints(pointVectors.at(0).toPointF(), pointVectors.at(1).toPointF());
    } else if (pointVectors.size() > 2)
    {
        // line probably goes through corner of rect, and we got two points there. single out the point pair with greatest distance:
        double distSqrMax = 0;
        QVector2D pv1, pv2;
        for (int i=0; i<pointVectors.size()-1; ++i)
        {
            for (int k=i+1; k<pointVectors.size(); ++k)
            {
                double distSqr = (pointVectors.at(i)-pointVectors.at(k)).lengthSquared();
                if (distSqr > distSqrMax)
                {
                    pv1 = pointVectors.at(i);
                    pv2 = pointVectors.at(k);
                    distSqrMax = distSqr;
                }
            }
        }
        result.setPoints(pv1.toPointF(), pv2.toPointF());
    }
    return result;
}


QPen PF_MeshLine::mainPen() const
{
    return mSelected ? mSelectedPen : mPen;
}

Line::Line(double x1, double y1, double x2, double y2):
    m_x1(x1),
    m_y1(y1),
    m_x2(x2),
    m_y2(y2)
{

}

Line::~Line()
{

}


}//namespace CommonFEM
